package icantalk.voip;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xiph.speex.SpeexDecoder;


/**
 * Thread used for receiving datagrams, buffering them and playing them
 *
 * @author Antonín Brettšnajdr
 */
class receiveThread implements Runnable {
    private DatagramSocket socket;
    private SoundIO snd;
    private SpeexDecoder speexDec;
    private long iseq;
    private long timestamp;
    final private ConcurrentLinkedQueue<byte[]> buffer;
    byte[] buf;
    private boolean first = true;
    
    private boolean isContinue = true;
    
    public void stopRunning()
    {
    	isContinue = false;
    }

    public receiveThread(DatagramSocket socket, SoundIO snd) {
        this.socket = socket;
        this.snd = snd;
        this.iseq = 0;
        this.buffer = new ConcurrentLinkedQueue<byte[]>();

    }

    public long getCurrentTimestamp() {
        return System.currentTimeMillis() - timestamp;
    }

    @Override
    public void run() {
        DatagramPacket packet;
        Packet parsed;
        this.timestamp = System.currentTimeMillis();
        long lag;

        new Thread(new Runnable() {

            private byte[] soundbuf;

            @Override
            public void run() {

                while (isContinue) {

                    if (buffer.size() >= 10) {
                        while (buffer.size() > 4) {
                            buffer.poll();
                        }
                    }

                    if (buffer.size() <= 1) {
                        while (buffer.size() < 4) {
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException ex) {
                                Logger.getLogger(receiveThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }

                    synchronized (buffer) {
                        soundbuf = buffer.poll();
                    }
                    try {
                        snd.writeSamples(soundbuf, 0, soundbuf.length);
                    } catch (IOException ex) {
                        Logger.getLogger(receiveThread.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }

            }
        }).start();

        while (isContinue) {
            try {
                buf = new byte[512];
                packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet);
                if (first) {
                    first = false;
                    main.setText("Speaking");
                }

                parsed = PacketFactory.parsePacket(packet);
                if (parsed == null) {
                    continue;
                }

                //iseq check
                if (parsed.getSeq() < iseq) {
                    //toss
                    System.out.println("Packet tossed: wrong sequence");
                    continue;
                }

                iseq = parsed.getSeq();

                buf = decodeWithSPEEX(parsed.getData());
                synchronized (buffer) {
                    buffer.offer(buf);
                }

            } catch (IOException ex) {
                Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }

    private byte[] decodeWithSPEEX(byte[] buff) {

        if (speexDec == null) {
            speexDec = new SpeexDecoder();
            speexDec.init(1, 8000, 1, true);
        }

        try {
            speexDec.processData(buff, 0, buff.length);
        } catch (Exception ex) {
            //exception
        }
        byte[] ret = new byte[speexDec.getProcessedDataByteSize()];
        speexDec.getProcessedData(ret, 0);

        return ret;
    }

}
